import com.powerfl.frm.taf.*;

import flash.utils.*;

private var _flows:Object;
private var _flowAutoKey:int;
private var _flowContext:String;
private var _flowContextBack:String;

private function flowInit():void{
	var describe:XML, className:String, key:*, method:String;
	
	_flowContextBack = _flowContext = '';
	_flows = {
		'@@KEY_ENTER':KEY_ENTER,
		'@@TWEEN_RA':TAFtween.runRA,
		'@@TWEEN_RA_A':TAFtween.RESUME_RA,
		'@@TWEEN_RA_D':TAFtween.PAUSE_RA,
		'@@TWEEN_RD':TAFtween.runRD,
		'@@TWEEN_RD_A':TAFtween.PAUSE_RD,
		'@@TWEEN_RD_D':TAFtween.RESUME_RD,
		'@@TWEEN_RF':TAFtween.runRF,
		'@@TWEEN_LA':TAFtween.runLA,
		'@@TWEEN_LA_A':TAFtween.RESUME_LA,
		'@@TWEEN_LA_D':TAFtween.PAUSE_LA,
		'@@TWEEN_LD':TAFtween.runLD,
		'@@TWEEN_LD_A':TAFtween.PAUSE_LD,
		'@@TWEEN_LD_D':TAFtween.RESUME_LD,
		'@@TWEEN_LF':TAFtween.runLF
	};
	describe = describeType( TAF );
	className = describe.@name[0].toString();
	for each( key in describe.method ){
		if( key.@declaredBy[0].toString() === className ){
			method = key.@name[0].toString();
			_flows[method] =  TAF[method];
			flowAlias( method, TAF[method] );
		}
	}
	for each( key in describe.factory.method ){
		if( key.@declaredBy[0].toString() === className ){
			method = key.@name[0].toString();
			_flows[method] = this[method];
			flowAlias( method, this[method] );
		}
	}
}
private function flowAlias( $name:String, $method:Function ):void{
	if( $name === 'equal' ){
		_flows['='] = $method;
	}else if( $name === 'not' ){
		_flows['!'] = $method;
	}else if( $name === 'numberLess' ){
		_flows['<'] = $method;
	}else if( $name === 'numberMore' ){
		_flows['>'] = $method;
	}else if( $name === 'plus' ){
		_flows['+'] = $method;
	}else if( $name === 'minus' ){
		_flows['-'] = $method;
	}else if( $name === 'numberMulti' ){
		_flows['*'] = $method;
	}else if( $name === 'numberDivide' ){
		_flows['/'] = $method;
	}else if( $name === 'numberModuler' ){
		_flows['%'] = $method;
	}else if( $name === 'numberPower' ){
		_flows['^'] = $method;
	}else if( $name === 'mathRand' ){
		_flows['~'] = $method;
	}else if( $name === 'mathRandN' ){
		_flows['~N'] = $method;
	}else if( $name === 'mathRandU' ){
		_flows['~U'] = $method;
	}else if( $name === 'objectGet' ){
		_flows['.'] = $method;
	}else if( $name === 'INT' ){
		_flows['int'] = $method;
	}else if( $name === 'UINT' ){
		_flows['uint'] = $method;
	}else if( $name === 'NUM' ){
		_flows['num'] = $method;
	}else if( $name === 'STR' ){
		_flows['str'] = $method;
	}else if( $name.substr( 0, 3 ) === 'add' ){
		_flows['+' + $name.charAt(3).toLowerCase() + $name.substr(4)] = $method;
	}else if( $name.substr( 0, 4 ) === 'bind' ){
		_flows['~' + $name.charAt(4).toLowerCase() + $name.substr(5)] = $method;
	}else if( $name.substr( 0, 6 ) === 'unbind' ){
		_flows['!' + $name.charAt(6).toLowerCase() + $name.substr(7)] = $method;
	}else if( $name.substr(-6) === 'Remove' ){
		_flows['-' + $name.substr( 0, $name.length - 6 )] = $method;
	}else if( $name.substr(-3) === 'Set' ){
		_flows['>' + $name.substr( 0, $name.length - 3 )] = $method;
	}else if( $name.substr(-3) === 'Get' ){
		_flows['<' + $name.substr( 0, $name.length - 3 )] = $method;
	}
}
final public function flowGet( $key:String ):Function{
	return SELF._flows[$key] || null; 
}
final public  function get flowContext():String{
	return SELF._flowContext;
}
final public function flowCall( $key:*, ...$param ):void{
	orderAdd( null, function():void{
		if( $key is Function ){
			$key.apply( null, $param );
		}else{
			flowGet( $key ).apply( null, $param );
		}
	} );
}
private function flowAdd( $flow:TAF ):void{
	var describe:XML, arg:Array, key:*, f:*, fkey:*, className:String, methodName:String;
	
	describe = describeType( $flow );
	className = describe.@name[0].toString();
	
	for each( key in describe.method ){
		if( key.@declaredBy[0].toString() === className ){
			methodName = key.@name[0].toString();
			flowAdd_( methodName, $flow[methodName] );
		}
	}
}
private function flowAdd_( $methodName:String, $method:* = null ):void{
	if( SELF._flows[$methodName] ){
		error( '이미 존재하는 flow입니다. - ' + $methodName );
	} 
	SELF._flows[$methodName] = function( ...$param ):void{
		flow_( $methodName, $method, $param );
	}
}
private function flow_( $methodName:String, $method:*, $param:Array ):void{
	var bind:*, key:*;
	SELF._flowContextBack = SELF._flowContext; 
	SELF._flowContext = $methodName;
	bind = SELF._bindFlowState[$methodName];
	if( bind ){
		for( key in bind ){
			if( stateGet( key ) === bind[key] ){}else{
				return;
			}
		} 
	}
	paramSet( $param ); 
	script( localScript );
	paramSet( null );
	if( $method ){
		if( $param.length ){
			$method.apply( null, $param );
		}else{
			$method();
		}
	}
	SELF._flowContext = SELF._flowContextBack;
}
private function flowAddMacro_( $methodName:String, $methods:Array ):void{
	if( SELF._flows[$methodName] ){
		error( '이미 존재하는 flow입니다. - ' + $methodName );
	} 
	SELF._flows[$methodName] = function( ...$param ):void{
		var i:int, j:int, bind:*, method:Function;
		for( i = 0, j = $methods.length ; i < j ; ++i ){
			if( $methods[i] is String ){
				method = flowGet( $methods[i] );
			}else if( $methods[i] is Function ){
				method = $methods[i];
			}
			method.apply( null, $param );
		}
	}
}
private function flowRemove( ...$flows ):void{
	var i:int, j:int;
	for( i = 0, j = $flows.length ; i < j ; ++i ){
		delete SELF._flows[$flows[i]];
	}
}
private function flowAutoKey():String{
	return '@@AUTOFLOW_' + (++SELF._flowAutoKey).toString();
}